#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <functional>
#include <future>
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits>
#include <vector>

class ThreadPool {
private:
  // 任务列表
  std::queue<std::function<void()>> m_tasks;
  // 线程列表
  std::vector<std::thread> m_threads;
  // 记录线程数量
  size_t m_numThreads;
  // 队列锁
  mutable std::mutex m_mutex;
  // 条件变量
  std::condition_variable task_condition;
  // 线程运行标志
  std::atomic<bool> m_running;
  // 空闲线程
  std::atomic<int> m_free_thread_num;
  // 任务完成条件变量
  std::condition_variable free_thread_cond;
  // 工作线程
  void worker();

public:
  ThreadPool(size_t numThreads = std::thread::hardware_concurrency());

  ~ThreadPool();

  // 提交任务
  template <typename F, typename... Args>
  auto submit(F &&f, Args &&...args)
      -> std::future<typename std::result_of<F(Args...)>::type> {
    // 获取任务返回类型
    using return_type = typename std::result_of<F(Args...)>::type;
    // 将任务包装为 packaged_task;
    auto task = std::make_shared<std::packaged_task<return_type()>>(
        std::bind(std::forward<F>(f), std::forward<Args>(args)...));
    // 获取future，用于外部获取结果
    std::future<return_type> res = task->get_future();
    // 将任务加入到队列
    {
      std::unique_lock<std::mutex> lock(m_mutex);
      if (!m_running.load()) {
        throw std::runtime_error(
            "ThreadPool has been stopped, cannot submit new tasks");
      }
      // 用lambda包装packaged_task, 转换为无参数无返回值的函数
      m_tasks.emplace([task]() { (*task)(); });
    }
    task_condition.notify_one();
    return res;
  }

  // 停止线程池
  void stop();
  // 线程池是否运行
  bool isRunning() const;
  // 任务队列大小
  size_t queueSize() const;
  // 工作线程数量
  size_t threadCount() const;
  // 等待所有任务完成
  void waitForAllTasks();
  // 清空任务队列
  void clearTasks();
};